#include<iostream>
#include<vector>
#include<queue>
#include"thread.hpp"
#include"lockguard.hpp"
namespace bit{
    template<class T>
    class ThreadPool{
    private:
        std::vector<Thread*> _threads;//用于存储找到所有线程的表
        int _num;//线程的数量
        std::queue<T> _task_queue;//任务队列
        static ThreadPool<T>* _pool_ptr;//线程池管理句柄，一种线程池只能出现一次
        static pthread_mutex_t _mtx;
        pthread_mutex_t lock;
        pthread_cond_t cond;
    public:
        pthread_mutex_t* getMutex(){
            return &lock;
        }
        bool isEmpty(){
            return _task_queue.empty();
        }
        void waitCond(){
            pthread_cond_wait(&cond,&lock);
        }
        T getTask(){
            T task = _task_queue.front();
            _task_queue.pop();
            return task;
        }
    private:
        ThreadPool(int num):_num(num){
            pthread_mutex_init(&lock,nullptr);
            pthread_cond_init(&cond,nullptr);
            for(int i=1;i<=_num;i++){
                std::string name="Thread"+std::to_string(i);
                _threads.push_back(new Thread(name,runtine,this));
            }
        }
    public:
        ~ThreadPool(){
            pthread_cond_broadcast(&cond);
            for(auto& x: _threads){
                x->join();
                delete x;
            }
            pthread_mutex_destroy(&lock);
            pthread_cond_destroy(&cond);
        }
        static ThreadPool<T>* getThreadPoolPtr(int num){
            if(_pool_ptr == nullptr){
                LockGuard tmp(&_mtx);
                if(!_pool_ptr){
                    _pool_ptr = new ThreadPool<T>(num);
                }
            }
            return _pool_ptr;
        }
        void push_task(const T& task){
            LockGuard tmp(&lock);
            _task_queue.push(task);
            pthread_cond_signal(&cond);
        }
        void run(){
            for(auto& x: _threads){
                x->start();
                std::cout<< x->name()<<"启动成功"<<std::endl;
            }
        }
        static void* runtine(void* arg){
            ThreadData* data = (ThreadData* ) arg;
            ThreadPool<T>* ptr = (ThreadPool<T>*)data->_args;
            while(true){
                T task;
                {
                    LockGuard tmp(ptr->getMutex());
                    while (ptr->isEmpty())
                    {
                        ptr->waitCond();
                    }
                    task = ptr->getTask();
                }
            }

        }
    };
    template<typename T>
    ThreadPool<T>* ThreadPool<T>::_pool_ptr = nullptr;
    template<typename T>
    pthread_mutex_t ThreadPool<T>::_mtx = PTHREAD_MUTEX_INITIALIZER;
}